﻿using NSubstitute;
using Sai.Core;
using Sai.Core.Introspection;
using Sai.Core.Reporting;
using Sai.Test.TestDataBuilders;
using Sai.Test.XUnit;
using System.IO;
using System.Xml.Serialization;
using Xunit;

namespace Sai.Test
{
    public class UnaryTypeChangeFacts
    {
        public class OnSerialization
        {
            [Fact, InMemoryTest]
            public void Basic_Construction_Reason_And_Message_Only_Are_Serialized()
            {
                UnaryTypeChange change = new UnaryTypeChange(TypeChangeReason.TypeTaxonomy, "This is a message");

                string output = ObjectFlattener<UnaryTypeChange>.Flatten(change);

                Assert.Contains("<UnaryTypeChange ", output);
                Assert.Contains("<Reason>TypeTaxonomy</Reason>", output);
                Assert.Contains("<Message>This is a message</Message>", output);
                Assert.Contains("</UnaryTypeChange>", output);
            }

            [Fact, InMemoryTest]
            public void SourceCode_Construction_Code_Is_Serialized()
            {
                SourceCode thisCode = new SourceCode();
                thisCode.Add(new TypeNameTag("ThisIsMyType"));

                ISourceCodeProvider provider = Substitute.For<ISourceCodeProvider>();
                provider.ToCode().Returns(thisCode);

                UnaryTypeChange change = new UnaryTypeChange(TypeChangeReason.TypeTaxonomy, provider, "This is a message");

                string output = ObjectFlattener<UnaryTypeChange>.Flatten(change);

                Assert.Contains("<UnaryTypeChange ", output);
                Assert.Contains("<Reason>TypeTaxonomy</Reason>", output);
                Assert.Contains("<Code>", output);
                Assert.Contains("ThisIsMyType", output);
                Assert.Contains("</Code>", output);
                Assert.Contains("<Message>This is a message</Message>", output);
                Assert.Contains("</UnaryTypeChange>", output);
            }
        }

        public class ObjectEquals
        {
            [Fact, InMemoryTest]
            public void Returns_True_For_Identical_MethodDeclarations()
            {
                string methodName = "Example";
                var returnType = new TypeName(new FullyQualifiedName("string"));

                var method1 = MethodDeclarationBuilder.Method()
                                .Named(methodName)
                                .WithReturnType(returnType)
                                .Build();

                UnaryTypeChange change1 = new UnaryTypeChange(
                    TypeChangeReason.MethodAdded, 
                    method1);

                var method2 = MethodDeclarationBuilder.Method()
                                .Named(methodName)
                                .WithReturnType(returnType)
                                .Build();

                UnaryTypeChange change2 = new UnaryTypeChange(
                    TypeChangeReason.MethodAdded,
                    method2);

                Assert.Equal(change1, change2);
            }

            [Fact, InMemoryTest]
            public void Returns_False_For_NonIdentical_MethodDeclarations()
            {
                string methodName = "Example";
                var returnType = new TypeName(new FullyQualifiedName("string"));

                var method1 = MethodDeclarationBuilder.Method()
                                .Named(methodName)
                                .WithReturnType(returnType)
                                .Build();

                UnaryTypeChange change1 = new UnaryTypeChange(
                    TypeChangeReason.MethodAdded,
                    method1);

                string methodName2 = "Example2";
                var method2 = MethodDeclarationBuilder.Method()
                                .Named(methodName2)
                                .WithReturnType(returnType)
                                .Build();

                UnaryTypeChange change2 = new UnaryTypeChange(
                    TypeChangeReason.MethodAdded,
                    method2);

                Assert.NotEqual(change1, change2);
            }

        }
    }
}
